﻿using ChongJu.ModelManager.Calibration;
using ChongJu.ModelManager.Camera;
using ChongJu.ModelManager.Config;
using ChongJu.ModelManager.DeviceInfo;
using ChongJu.ModelManager.Rating;
using Public.Logger;
using Public.Tools;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;


namespace ChongJu.GlobalInfo
{
    public class AllConfigModel
    {
        public string PLCConfig { get; set; }

        private bool IsLocalConfig { get; set; } = false;

        public CameraModel Camera { get; set; }
        public CalibrationCfgModel Calibration { get; set; }
        public GlobalConfigModel Global { get; set; }
        public List<SerialPortModel> SerialPorts { get; set; }

        public FileTransModel FileTransConfig { get; set; }

        private bool PLCIsRight { get; set; }
        public AllConfigModel()
        {
            //读取配置文件
            ReadConfig(false);
            // List<> JsonToObject 会追加而不是删除
            SerialPorts = null;
            CheckConfigRight();
        }

        /// <summary>
        /// 有参数构造时表示直接读取文件来初始化此类
        /// </summary>
        public AllConfigModel(bool isLocal, bool checkConfig)
        {
            //读取配置文件
            ReadConfig(isLocal);
            //把错误的配置置为null
            if (checkConfig)
                CheckConfigRight();
        }


        /// <summary>
        /// 从文件里面读取配置文件
        /// </summary>
        private void ReadConfig(bool isLocal)
        {
            //todo 优化成反射加注解来获取配置数据
            if (File.Exists(ConfigFileInfo.CamereConfig) == true)
                Camera = GetConfig<CameraModel>(Tool.Read(ConfigFileInfo.CamereConfig));

            if (File.Exists(ConfigFileInfo.CalibrationConfig) == true)
                Calibration = GetConfig<CalibrationCfgModel>(Tool.Read(ConfigFileInfo.CalibrationConfig));

            if (File.Exists(ConfigFileInfo.GlobalConfig) == true)
                Global = GetConfig<GlobalConfigModel>(Tool.Read(ConfigFileInfo.GlobalConfig));

            if (File.Exists(ConfigFileInfo.SerialConfig) == true)
                SerialPorts = GetConfig<List<SerialPortModel>>(Tool.Read(ConfigFileInfo.SerialConfig));

            if (File.Exists(ConfigFileInfo.PlcPortConfig) == true)
                PLCConfig = Tool.Read(ConfigFileInfo.PlcPortConfig);

            if (File.Exists(ConfigFileInfo.FileTransCfg) == true)
                FileTransConfig = GetConfig<FileTransModel>(Tool.Read(ConfigFileInfo.FileTransCfg));

            IsLocalConfig = isLocal;
        }

        public void WriteConfigToFile()
        {
            //todo 优化成反射加注解，配置路径以及是否改变数值
            //重新赋值，正确的则写入文件，只有改为反射加注解的方式时从方法可以不调用
            CheckConfigRight();
            if (null != Camera && !Tool.Wirte(ConfigFileInfo.CamereConfig, Tool.ObjectToJson(Camera)))
                Logger.Error($"WriteConfigToFile 写入相机配置失败");

            if (null != Calibration && !Tool.Wirte(ConfigFileInfo.CalibrationConfig, Tool.ObjectToJson(Calibration)))
                Logger.Error($"WriteConfigToFile 写入校准配置失败");

            //if (null != Global && !Tool.Wirte(ConfigFileInfo.GlobalConfig, Tool.ObjectToJson(Global)))
            //    Logger.Error($"WriteConfigToFile 写入全局参数配置失败");

            //if (null != SerialPorts && SerialPorts.Count > 0 && !Tool.Wirte(ConfigFileInfo.SerialConfig, Tool.ObjectToJson(SerialPorts)))
            //    Logger.Error($"WriteConfigToFile 写入端口配置失败");

            //if (PLCIsRight && !Tool.Wirte(ConfigFileInfo.PlcPortConfig, PLCConfig))
            //    Logger.Error($"WriteConfigToFile 写入PLC配置失败");

            if (null != FileTransConfig && !Tool.Wirte(ConfigFileInfo.FileTransCfg, Tool.ObjectToJson(FileTransConfig)))
                Logger.Error($"WriteConfigToFile 写入FileTransConfig失败");

            //把配置写到内存
            WriteGlobalToMemory();
        }

        /// <summary>
        /// 检查配置文件是否正确
        /// </summary>
        /// <returns>true:正确;false:错误</returns>
        public bool CheckConfigRight()
        {
            PLCIsRight = CheckPLCConfig();
            return null != Camera || null != Calibration || null != Global || (null != SerialPorts && SerialPorts.Count > 0) || PLCIsRight || null != FileTransConfig;
        }

        private T GetConfig<T>(string configTxt)
        {
            T config = default(T);
            if (string.IsNullOrEmpty(configTxt))
                return config;

            try
            {
                config = Tool.JsonToObject<T>(configTxt);
            }
            catch (Exception ex)
            {
                Logger.Error($"==检查{config.GetType().Name}配置参数失败=={ex}");
            }

            return config;
        }

        private bool CheckPLCConfig()
        {
            if (PLCConfig == null)
                return false;

            //string[] txts = Regex.Split(PLCConfig, "\r\n");
            List<string> PLCSettings = PLCConfig.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries).ToList();
            //PLC的设置项总共79个，如果小于79个代表配置不正确，可以多，但是不能少
            if (null == PLCSettings || PLCSettings.Count < 79)
            {
                Logger.Error($"=== AllConfigModel检查{(IsLocalConfig ? "本地" : "云端")}PLC配置,配置数量{PLCSettings.Count}不正确 ===");
                PLCConfig = null;
                return false;
            }

            Dictionary<string, int> configCountMap = GetConfigCountMap(PLCSettings);
            bool plcIsRight = CheckPLCCountIsRight(configCountMap);
            if(!plcIsRight)
                PLCConfig = null;
            return plcIsRight;
        }

        private Dictionary<string, int> GetConfigCountMap(List<string> PLCSettings)
        {
            Dictionary<string, int> configCountMap = new Dictionary<string, int>();
            foreach (string config in PLCSettings)
            {
                string[] detailConfigArr = config.Split(new string[] { "\t", " " }, StringSplitOptions.RemoveEmptyEntries);
                if (detailConfigArr.Length != 3)
                {
                    Logger.Error($"=== AllConfigModel检查{(IsLocalConfig ? "本地" : "云端")}PLC配置{config}不正确 ===");
                    return null;
                }

                if (config.Contains("启停"))
                    GetAndSetPLCDetailConfigCount("启停", configCountMap);
                else if (config.Contains("等级"))
                    GetAndSetPLCDetailConfigCount("等级", configCountMap);
                else if (config.Contains("传送带"))
                    GetAndSetPLCDetailConfigCount("传送带", configCountMap);
                else if (config.Contains("分拣气缸"))
                    GetAndSetPLCDetailConfigCount("分拣气缸", configCountMap);
                else if (config.Contains("下料气缸"))
                    GetAndSetPLCDetailConfigCount("下料气缸", configCountMap);
                else if (config.Contains("滚筒"))
                    GetAndSetPLCDetailConfigCount("滚筒", configCountMap);
                else if (config.Contains("缓存"))
                    GetAndSetPLCDetailConfigCount("缓存", configCountMap);
                else if (config.Contains("小车皮带速度"))
                    GetAndSetPLCDetailConfigCount("小车皮带速度", configCountMap);
                else if (config.Contains("通道时间范围下限"))
                    GetAndSetPLCDetailConfigCount("通道时间范围下限", configCountMap);
                else if (config.Contains("通道时间范围上限"))
                    GetAndSetPLCDetailConfigCount("通道时间范围上限", configCountMap);
                else if (config.Contains("其他参数"))
                    GetAndSetPLCDetailConfigCount("其他参数", configCountMap);
            }

            return configCountMap;
        }

        private void GetAndSetPLCDetailConfigCount(string configKey, Dictionary<string, int> configCountMap)
        {
            if (configCountMap.ContainsKey(configKey))
                configCountMap[configKey] += 1;
            else
                configCountMap.Add(configKey, 1);
        }

        private bool CheckPLCCountIsRight(Dictionary<string, int> configCountMap)
        {
            //如果不能转换成map代表失败，则返回false
            if (null == configCountMap || configCountMap.Count <= 0)
                return false;

            return configCountMap.ContainsKey("启停") && 1 == configCountMap["启停"] &&
                configCountMap.ContainsKey("等级") && 1 == configCountMap["等级"] &&
                configCountMap.ContainsKey("缓存") && 1 == configCountMap["缓存"] &&
                configCountMap.ContainsKey("传送带") && 7 == configCountMap["传送带"] &&
                configCountMap.ContainsKey("分拣气缸") && 13 == configCountMap["分拣气缸"] &&
                configCountMap.ContainsKey("下料气缸") && 13 == configCountMap["下料气缸"] &&
                configCountMap.ContainsKey("滚筒") && 11 == configCountMap["滚筒"] &&
                configCountMap.ContainsKey("小车皮带速度") && 9 == configCountMap["小车皮带速度"] &&
                configCountMap.ContainsKey("通道时间范围下限") && 9 == configCountMap["通道时间范围下限"] &&
                configCountMap.ContainsKey("通道时间范围上限") && 9 == configCountMap["通道时间范围上限"] &&
                configCountMap.ContainsKey("其他参数") && 5 == configCountMap["其他参数"];
        }

        private void WriteGlobalToMemory()
        {
            try
            {
                Type clazz = Global.GetType();
                FieldInfo[] fields = clazz.GetFields();
                foreach (FieldInfo field in fields)
                {
                    string fieldName = field.Name;
                    //IsClearing不能随便写，需要控制
                    if ("IsClearing".Equals(fieldName))
                        continue;

                    field.SetValue(GlobalVar.GlobalParamer, field.GetValue(Global));
                }
            }
            catch (Exception ex)
            {
                Logger.Error($"=== WriteGlobalToMemory Error ===", ex);
            }
        }

    }
}
